home *** CD-ROM | disk | FTP | other *** search
/ MACD 5 / MACD 5.bin / workbench / tools / czesc_2 / fifolib / fifo-handler.c < prev    next >
C/C++ Source or Header  |  1991-12-06  |  25KB  |  1,110 lines

  1.  
  2. /*
  3.  *  FIFO-HANDLER.C    V37.4
  4.  *
  5.  *  Provide an interface to the fifo.library
  6.  *  Provide remote shell support, including "*" support and interactive
  7.  *  support.
  8.  *
  9.  *  !!! MUST BE RUN, CANNOT USE MOUNT !!!
  10.  *
  11.  *  FIFO:fifo_name/flags
  12.  *           r    for reading
  13.  *           w    for writing
  14.  *           c    cooked (else raw)
  15.  *           e    EOF on close (if a writer)
  16.  *           k    allows writer to close before reader opens without
  17.  *            any data lost.
  18.  *           K    a reader MUST exist or write(s) will fail
  19.  *           q    QUIT (debugging)
  20.  *           m    master
  21.  *           t    tee off the read stream (no interference with other
  22.  *            readers)
  23.  *           s    shell
  24.  *
  25.  *           d    debug mode (read by running 'RemCLI DBFifo')
  26.  */
  27.  
  28. #define CLI_START
  29.  
  30. #include "handler.h"
  31. #include "fifo.h"
  32. #include <lists.h>
  33. #include <string.h>
  34.  
  35. #define FIFO_SIZE   2048
  36.  
  37. #define SIGS    (SIGBREAKF_CTRL_C|SIGBREAKF_CTRL_D|SIGBREAKF_CTRL_E|SIGBREAKF_CTRL_F)
  38.  
  39. void myexit(int);
  40. void Initialize(void);
  41. void returnpacket(DosPacket *);
  42. void HandleRequestMsg(Message *);
  43. void WaitMsg(Message *);
  44. void SigHandles(char *, long);
  45. void xprintf(char *, ...);
  46. void *DosAllocMem(long);
  47. int OpenHandle(FHan *, char *, char *, long, long, long);
  48. void CloseHandle(FHan *);
  49. void DosFree(void *);
  50. MsgPort *SpecPort(FHan *);
  51. void MkDevice(char *);
  52. void DelDevice(void);
  53.  
  54. short        DDebug;
  55. short        NotDone = 1;
  56. MsgPort     *IoSink;
  57. MsgPort     *PktPort;
  58. #ifndef CLI_START
  59. DeviceNode  *DevNode;
  60. #endif
  61. void        *FifoBase;
  62. long        PktPortMask;
  63. #ifdef DEBUG
  64. long        DBFifo;
  65. #endif
  66.  
  67. List    HanList;
  68.  
  69. extern struct DosLibrary *DOSBase;
  70.  
  71. __stkargs void
  72. _main(arg, len)
  73. char *arg;
  74. long len;
  75. {
  76.     DosPacket  *packet;
  77.  
  78.     NewList((MaxList *)&HanList);
  79.  
  80.     Initialize();
  81.  
  82.     /*
  83.      *    Main Loop
  84.      */
  85.  
  86.     while (NotDone || GetHead(&HanList)) {
  87.     {
  88.         Message *msg;
  89.  
  90.         while (msg = GetMsg(IoSink))
  91.         HandleRequestMsg(msg);
  92.         if ((msg = GetMsg(PktPort)) == NULL) {
  93.         if (Wait(SIGS | PktPortMask) & SIGBREAKF_CTRL_C)
  94.             NotDone = 0;
  95.         continue;
  96.         }
  97.         packet = (DosPacket *)msg->mn_Node.ln_Name;
  98.     }
  99.     if (packet->dp_Type != ACTION_WRITE)
  100.         packet->dp_Res1 = DOS_TRUE;
  101.     packet->dp_Res2 = 0;
  102.  
  103. #ifdef DEBUG
  104.     if (DDebug)
  105.         xprintf("packet %08lx (%d)\n", packet->dp_Type, packet->dp_Type);
  106. #endif
  107.  
  108.     switch(packet->dp_Type) {
  109.     case ACTION_DIE:
  110.         NotDone = 0;
  111.         break;
  112.     case ACTION_FINDUPDATE:     /*    FileHandle,Lock,Name        Bool    */
  113.     case ACTION_FINDINPUT:        /*    FileHandle,Lock,Name        Bool    */
  114.     case ACTION_FINDOUTPUT:     /*    FileHandle,Lock,Name        Bool    */
  115.  
  116.         {
  117.         FileHandle *fh = BTOC(packet->dp_Arg1);
  118.         FHan *han;
  119.         char fifo_name_m[128];
  120.         char fifo_name_s[128];
  121.         short error = 0;
  122.         long han_flags = 0;
  123.         long opn_flags = FIFOF_NORMAL | FIFOF_NBIO;
  124.         long opn_size  = FIFO_SIZE;
  125.  
  126.         {
  127.             char *bas = BTOC(packet->dp_Arg3);
  128.             char *ptr;
  129.             unsigned char len = *(unsigned char *)bas;
  130.             long sigs = 0;
  131.  
  132. #ifdef DEBUG
  133.             if (DDebug)
  134.             xprintf("open: %*.*s\n", len, len, bas + 1);
  135. #endif
  136.             for (ptr = ++bas; *ptr != ':' && len; ++ptr, --len);
  137.             if (len && *ptr == ':') {
  138.             ++ptr;
  139.             --len;
  140.             } else {
  141.             len = ptr - bas;
  142.             ptr = bas;
  143.             }
  144.             bas = ptr;
  145.             for (ptr = bas; *ptr != '/' && len; ++ptr, --len);
  146.             {
  147.             int i = ptr - bas;
  148.             strncpy(fifo_name_m, bas, i);
  149.             strncpy(fifo_name_s, bas, i);
  150.             strcpy(fifo_name_m + i, "_m");
  151.             strcpy(fifo_name_s + i, "_s");
  152.             }
  153.             if (len && *ptr == '/') {
  154.             for (++ptr, --len; len; ++ptr, --len) {
  155.                 switch(*ptr) {
  156.                 case 'q':
  157.                 NotDone = 0;
  158.                 break;
  159.                 case 'e':
  160.                 han_flags |= FHF_CLOSEEOF;
  161.                 break;
  162.                 case 'c':
  163.                 han_flags |= FHF_COOKED;
  164.                 break;
  165.                 case 'r':
  166.                 han_flags |= FHF_READ;
  167.                 break;
  168.                 case 'w':
  169.                 han_flags |= FHF_WRITE;
  170.                 break;
  171.                 case 'k':
  172.                 opn_flags |= FIFOF_KEEPIFD;
  173.                 break;
  174.                 case 'K':
  175.                 opn_flags |= FIFOF_RREQUIRED;
  176.                 break;
  177.                 case 'm':
  178.                 han_flags |= FHF_MASTER;
  179.                 break;
  180.                 case 't':
  181.                 han_flags |= FHF_TEE;
  182.                 break;
  183.                 case 'd':
  184. #ifdef DEBUG
  185.                 if (DDebug == 0) {
  186.                     DDebug = 1;
  187.                     DBFifo = OpenFifo("DBFifo_s", 1024, FIFOF_WRITE | FIFOF_NORMAL);
  188.                 }
  189. #endif
  190.                 break;
  191.                 case 'x':
  192. #ifdef DEBUG
  193.                 if (DDebug) {
  194.                     DDebug = 0;
  195.                     if (DBFifo)
  196.                     CloseFifo(DBFifo, FIFOF_EOF);
  197.                     DBFifo = NULL;
  198.                 }
  199. #endif
  200.                 break;
  201.                 case 's':
  202.                 han_flags |= FHF_SHELL;
  203.                 break;
  204.                 case 'C':
  205.                 sigs |= SIGBREAKF_CTRL_C;
  206.                 break;
  207.                 case 'D':
  208.                 sigs |= SIGBREAKF_CTRL_D;
  209.                 break;
  210.                 case 'E':
  211.                 sigs |= SIGBREAKF_CTRL_E;
  212.                 break;
  213.                 case 'F':
  214.                 sigs |= SIGBREAKF_CTRL_F;
  215.                 break;
  216.                 default:
  217.                 error = 1;
  218.                 break;
  219.                 }
  220.             }
  221.             }
  222.             if (sigs) {
  223.             if (han_flags & FHF_MASTER)
  224.                 SigHandles(fifo_name_m, sigs);
  225.             else
  226.                 SigHandles(fifo_name_s, sigs);
  227.             }
  228.         }
  229.  
  230.         /*
  231.          *  To handle the stderr channel, "*", an interactive
  232.          *  shell must be openned with the 's' flag, which causes
  233.          *  a special message port to be created for the interactive
  234.          *  shell (and thus the pr_ConsoleTask field)
  235.          *
  236.          *  To handle COOKED data mode, FIFO: itself must processed
  237.          *  received data before the slave device, echoing it back
  238.          *  on the master channel and doing other cooked processing.
  239.          */
  240.  
  241.         if (error == 0) {
  242.             if (strcmp(fifo_name_m, "*_m") == 0) {
  243.             if (fh->fh_Port && (long)fh->fh_Port != -1) {
  244.                 han = (FHan *)fh->fh_Port->mp_Node.ln_Name;
  245.                 ++han->ff_Refs;
  246.                 fh->fh_Arg1 = han;
  247.                 fh->fh_Port = (MsgPort *)DOS_TRUE;
  248.                 break;
  249.             }
  250.             fh->fh_Port = (MsgPort *)DOS_FALSE;
  251.             packet->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  252.             break;
  253.             }
  254.  
  255.             if (han = AllocMem(sizeof(FHan) + strlen(fifo_name_s) + 1, MEMF_CLEAR | MEMF_PUBLIC)) {
  256.             han->ff_Node.ln_Name = (char *)(han + 1);
  257.             if (OpenHandle(han, fifo_name_s, fifo_name_m, han_flags, opn_size, opn_flags) >= 0) {
  258.                 if (han_flags & FHF_SHELL) {
  259.                 han->ff_Port = SpecPort(han);
  260.                 fh->fh_Type = han->ff_Port;
  261.                 }
  262.                 fh->fh_Arg1 = han;
  263.                 fh->fh_Port = (MsgPort *)DOS_TRUE;
  264.                 AddTail((MaxList *)&HanList, &han->ff_Node);
  265.                 ++han->ff_Refs;
  266.                 han->ff_Flags = han_flags;
  267.                 han->ff_RdMsg.mn_ReplyPort = IoSink;
  268.                 han->ff_RdMsg.mn_Node.ln_Name = (char *)han;
  269.                 han->ff_WrMsg.mn_ReplyPort = IoSink;
  270.                 han->ff_WrMsg.mn_Node.ln_Name = (char *)han;
  271.                 han->ff_Task = packet->dp_Port->mp_SigTask;
  272.                 /*
  273.                 han->ff_Task = ((Message *)packet->dp_Link)->mn_ReplyPort->mp_SigTask;
  274.                 */
  275.                 if (han_flags & FHF_WRITE)
  276.                 han->ff_FBufSiz = BufSizeFifo(han->ff_FifoW);
  277.                 NewList((MaxList *)&han->ff_RdWait);
  278.                 NewList((MaxList *)&han->ff_WrWait);
  279.                 if (han_flags & FHF_COOKED) {
  280.                 RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  281.                 han->ff_Flags |= FHF_RPEND;
  282.                 han->ff_CookBuf = AllocMem(CB_SIZE, MEMF_PUBLIC | MEMF_CLEAR);
  283.                 }
  284.                 break;
  285.             }
  286.             AddTail((MaxList *)&HanList, &han->ff_Node);
  287.             CloseHandle(han);
  288.             }
  289.         }
  290.         fh->fh_Port = (MsgPort *)DOS_FALSE;
  291.         packet->dp_Res2 = ERROR_OBJECT_NOT_FOUND;
  292. #ifdef DEBUG
  293.         if (DDebug)
  294.             xprintf("open failed\n");
  295. #endif
  296.         }
  297.         break;
  298.     case ACTION_READ:        /*    FHArg1,CPTRBuffer,Length    ActLength    */
  299.         /*
  300.          *    read from fifo.  If we are in cooked mode this action is
  301.          *    only able to read from the cooked buffer, and then only
  302.          *    if a line is complete.
  303.          */
  304.  
  305.         {
  306.         FHan *han = (FHan *)packet->dp_Arg1;
  307.         char *ptr;
  308.         long n;
  309.  
  310.         if (!(han->ff_Flags & FHF_READ)) {
  311.             packet->dp_Res1 = -1;
  312.             break;
  313.         }
  314.         if (han->ff_Flags & FHF_REOF) {
  315.             han->ff_Flags &= ~FHF_REOF;
  316.             packet->dp_Res1 = 0;
  317.             break;
  318.         }
  319.         if (han->ff_Flags & FHF_COOKED) {
  320.             long n;
  321.             if ((n = strlen(han->ff_CookBuf)) != han->ff_CookIdx || han->ff_LRet) {
  322.             ++n;
  323.             if (n > packet->dp_Arg3)
  324.                 n = packet->dp_Arg3;
  325.             else
  326.                 han->ff_CookBuf[n-1] = '\n';
  327.             movmem(han->ff_CookBuf, (void *)packet->dp_Arg2, n);
  328.             movmem(han->ff_CookBuf + n, han->ff_CookBuf, han->ff_CookIdx - n + 1);
  329.             han->ff_CookIdx -= n;
  330.             if (han->ff_CookIdx == 0)
  331.                 han->ff_LRet = 0;
  332.             packet->dp_Res1 = n;
  333.  
  334.             /*
  335.              *  if we blocked on reading the fifo to cook more
  336.              *  data, we unblock it here.
  337.              */
  338.  
  339.             han->ff_Flags &= ~FHF_COOKBFUL;
  340.             if ((han->ff_Flags & FHF_RPEND) == 0) {
  341.                 RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  342.                 han->ff_Flags |= FHF_RPEND;
  343.             }
  344.             break;
  345.             } else {
  346.             if (han->ff_Flags & FHF_REOF) {
  347.                 han->ff_Flags &= ~FHF_REOF;
  348.                 packet->dp_Res1 = 0;
  349.                 break;
  350.             }
  351.             }
  352.         } else {
  353.             n = ReadFifo(han->ff_FifoR, &ptr, 0);
  354.             if (n < 0 || (n == 0 && (han->ff_Flags & FHF_REOF))) {
  355.             han->ff_Flags &= ~FHF_REOF;
  356.             packet->dp_Res1 = 0;
  357.             break;
  358.             }
  359.             if (n > 0) {
  360.             if (n > packet->dp_Arg3)
  361.                 n = packet->dp_Arg3;
  362.             movmem(ptr, (void *)packet->dp_Arg2, n);
  363.             if (ReadFifo(han->ff_FifoR, &ptr, n) < 0)
  364.                 han->ff_Flags |= FHF_REOF;
  365.             packet->dp_Res1 = n;
  366.             break;
  367.             }
  368.         }
  369.  
  370.         /*
  371.          *  blocked
  372.          */
  373.  
  374.         AddTail((MaxList *)&han->ff_RdWait, &((Message *)packet->dp_Link)->mn_Node);
  375.         if ((han->ff_Flags & FHF_RPEND) == 0) {
  376.             RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  377.             han->ff_Flags |= FHF_RPEND;
  378.         }
  379.         packet = NULL;
  380.         }
  381.         break;
  382.     case ACTION_WRITE:        /*    FHArg1,CPTRBuffer,Length    ActLength    */
  383.         {
  384.         FHan *han = (FHan *)packet->dp_Arg1;
  385.         long n;
  386.         long i;
  387.  
  388.         if (!(han->ff_Flags & FHF_WRITE)) {
  389.             packet->dp_Res1 = -1;
  390.             break;
  391.         }
  392.  
  393.         i = packet->dp_Arg3;
  394. #ifdef DEBUG
  395.         if (DDebug)
  396.             xprintf("i = %d\n", i);
  397. #endif
  398.         if (i < 0) {    /*  re-scan     */
  399.             i = -i;
  400.             packet->dp_Arg3 = i;
  401.         } else {    /*  initial pkt */
  402.             packet->dp_Res1 = 0;
  403.         }
  404.  
  405.  
  406.         /*
  407.          *  check for output stopped due to pending input line
  408.          *
  409.          *  dp_Arg3 < 0 indicates a re-scan (so we do not clear
  410.          *  our dp_Res1 field that is tracking the amnt written)
  411.          */
  412.  
  413.         if ((han->ff_Flags & FHF_COOKED) && han->ff_CookIdx && han->ff_LRet == 0) {
  414.             packet->dp_Arg3 = -packet->dp_Arg3;
  415.             AddTail((MaxList *)&han->ff_WrWait, &((Message *)packet->dp_Link)->mn_Node);
  416.             han->ff_Flags |= FHF_WIHOLD;
  417.             packet = NULL;
  418.             break;
  419.         }
  420.  
  421.  
  422.         /*
  423.          *  limit size of writes to fifo to something the fifo can
  424.          *  handle.  If cooked mode writer, prepend CR to LF's.
  425.          */
  426.  
  427.         if (i > (han->ff_FBufSiz >> 1) - 1)
  428.             i = (han->ff_FBufSiz >> 1) - 1;
  429.  
  430.         if (han->ff_Flags & FHF_COOKED) {
  431.             char *ptr = (char *)packet->dp_Arg2;
  432.             long j;
  433.  
  434.             for (j = 0; j < i; ++j) {
  435.             if (ptr[j] == '\n') {
  436.                 if (j == 0) {
  437.                 n = WriteFifo(han->ff_FifoW, "\r\n", 2);
  438.                 if (n == 2)
  439.                     n = 1;    /*  skip LF */
  440.                 break;
  441.                 }
  442.                 n = WriteFifo(han->ff_FifoW, ptr, j);
  443.                 break;
  444.             }
  445.             }
  446.             if (i == j)
  447.             n = WriteFifo(han->ff_FifoW, (char *)packet->dp_Arg2, i);
  448.         } else {
  449.             n = WriteFifo(han->ff_FifoW, (char *)packet->dp_Arg2, i);
  450.         }
  451.  
  452.         /*
  453.          *  object too large or broken pipe
  454.          */
  455.  
  456.         if (n < 0) {
  457.             packet->dp_Res1 = -1;
  458.             packet->dp_Res2 = ERROR_OBJECT_TOO_LARGE;
  459.             break;
  460.         }
  461. #ifdef DEBUG
  462.         if (DDebug)
  463.             xprintf("n = %d, res1 = %d,  i=%d\n", n, packet->dp_Res1 + n, i);
  464. #endif
  465.         packet->dp_Res1 += n;
  466.         if (n == packet->dp_Arg3)
  467.             break;
  468.  
  469.         packet->dp_Arg3 = -(packet->dp_Arg3 - n);
  470.         packet->dp_Arg2 += n;
  471.  
  472.         /*
  473.          *  blocked
  474.          *  n == 0
  475.          */
  476.  
  477. #ifdef DEBUG
  478.         if (DDebug)
  479.             xprintf("AddTail:res1 = %d\n", packet->dp_Res1);
  480. #endif
  481.  
  482.         AddTail((MaxList *)&han->ff_WrWait, &((Message *)packet->dp_Link)->mn_Node);
  483.         if ((han->ff_Flags & FHF_WAVAIL) == 0) {
  484.             RequestFifo(han->ff_FifoW, &han->ff_WrMsg, FREQ_WAVAIL);
  485.             han->ff_Flags |= FHF_WAVAIL;
  486.         }
  487.         packet = NULL;
  488.         }
  489.         break;
  490.     case ACTION_REQUEST:        /*    FHArg1, msg, how        Bool    */
  491.         {
  492.         FHan *han = (FHan *)packet->dp_Arg1;
  493.  
  494.         if ((unsigned short)packet->dp_Arg3 == FREQ_RPEND) {
  495.             if (han->ff_FifoR)
  496.             RequestFifo(han->ff_FifoR, (void *)packet->dp_Arg2, packet->dp_Arg3);
  497.             else
  498.             packet->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  499.             break;
  500.         } else if ((unsigned short)packet->dp_Arg3 == FREQ_WAVAIL) {
  501.             if (han->ff_FifoW)
  502.             RequestFifo(han->ff_FifoW, (void *)packet->dp_Arg2, packet->dp_Arg3);
  503.             else
  504.             packet->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  505.             break;
  506.         } else if ((unsigned short)packet->dp_Arg3 == FREQ_ABORT) {
  507.             if (han->ff_FifoR)
  508.             RequestFifo(han->ff_FifoR, (void *)packet->dp_Arg2, packet->dp_Arg3);
  509.             if (han->ff_FifoW)
  510.             RequestFifo(han->ff_FifoW, (void *)packet->dp_Arg2, packet->dp_Arg3);
  511.         } else {
  512.             packet->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  513.         }
  514.         }
  515.         break;
  516.     case ACTION_END:        /*    FHArg1                Bool:TRUE    */
  517.         {
  518.         FHan *han = (FHan *)packet->dp_Arg1;
  519.         Message *msg;
  520.  
  521.         if (--han->ff_Refs == 0) {
  522.             if (han->ff_Flags & FHF_RPEND) {
  523.             RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_ABORT);
  524.             WaitMsg(&han->ff_RdMsg);
  525.             }
  526.             if (han->ff_Flags & FHF_WAVAIL) {
  527.             RequestFifo(han->ff_FifoW, &han->ff_WrMsg, FREQ_ABORT);
  528.             WaitMsg(&han->ff_WrMsg);
  529.             }
  530.             returnpacket(packet);   /* before ff_Port goes away */
  531.             CloseHandle(han);
  532.             packet = NULL;
  533.         }
  534.         }
  535.         break;
  536.     case ACTION_SCREEN_MODE:
  537.         if (packet->dp_Arg2 && packet->dp_Arg2 != -1) {
  538.         FHan *han = (FHan *)(((MsgPort *)packet->dp_Arg2)->mp_Node.ln_Name);
  539.  
  540. #ifdef DEBUG
  541.         if (DDebug)
  542.             xprintf("handle %s arg1 %d\n", han->ff_Node.ln_Name, packet->dp_Arg1);
  543. #endif
  544.  
  545.         switch (packet->dp_Arg1) {
  546.         case DOS_TRUE:        /*    RAW    */
  547.             if (han->ff_Flags & FHF_COOKED) {
  548.             han->ff_Flags &= ~(FHF_COOKED|FHF_WIHOLD|FHF_COOKECHOBLK|FHF_COOKBFUL);
  549.  
  550.             if ((han->ff_Flags & FHF_READ) && !(han->ff_Flags & FHF_RPEND)) {
  551.                 RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  552.                 han->ff_Flags |= FHF_RPEND;
  553.             }
  554.             if ((han->ff_Flags & FHF_WRITE) && !(han->ff_Flags & FHF_WAVAIL)) {
  555.                 RequestFifo(han->ff_FifoW, &han->ff_WrMsg, FREQ_WAVAIL);
  556.                 han->ff_Flags |= FHF_WAVAIL;
  557.             }
  558.             }
  559.             break;
  560.         case DOS_FALSE:     /*    COOKED    */
  561.             if (!(han->ff_Flags & FHF_COOKED)) {
  562.             han->ff_Flags |= FHF_COOKED;
  563.  
  564.             }
  565.             break;
  566.         }
  567.         }
  568.         break;
  569.     case ACTION_SEEK:        /*    FHArg1,Position,Mode        OldPosition */
  570.     default:
  571.         packet->dp_Res2 = ERROR_ACTION_NOT_KNOWN;
  572.         break;
  573.     }
  574.     if (packet) {
  575.         if (packet->dp_Res2)
  576.         packet->dp_Res1 = DOS_FALSE;
  577.         returnpacket(packet);
  578.     }
  579.     }
  580.     myexit(0);
  581. }
  582.  
  583. int
  584. OpenHandle(han, r_name, w_name, han_flags, opn_size, opn_flags)
  585. FHan *han;
  586. char *r_name;    /*  slave name    */
  587. char *w_name;    /*  master name */
  588. long han_flags;
  589. long opn_size;
  590. long opn_flags;
  591. {
  592.     if (han_flags & FHF_MASTER) {
  593.     strcpy(han->ff_Node.ln_Name, w_name);
  594.     } else {
  595.     char *swap;
  596.     strcpy(han->ff_Node.ln_Name, r_name);
  597.     swap = r_name;
  598.     r_name = w_name;
  599.     w_name = swap;
  600.     }
  601.  
  602.     if ((han_flags & FHF_TEE) == 0 && (han_flags & FHF_READ)) {
  603.     FHan *h2;
  604.     for (h2 = (FHan *)HanList.mlh_Head; h2->ff_Node.ln_Succ; h2 = (FHan *)h2->ff_Node.ln_Succ) {
  605.         if (strcmp(h2->ff_Node.ln_Name, han->ff_Node.ln_Name) == 0) {
  606.         if ((h2->ff_Flags & FHF_TEE) == 0 && h2->ff_SRead) {
  607.             han->ff_SRead = h2->ff_SRead;
  608.             ++han->ff_SRead->sr_Refs;
  609.             break;
  610.         }
  611.         }
  612.     }
  613.     }
  614.  
  615.     if ((han_flags & FHF_READ) && han->ff_SRead == NULL) {
  616.     han->ff_SRead = AllocMem(sizeof(SharRead), MEMF_CLEAR | MEMF_PUBLIC);
  617.     han->ff_SRead->sr_FifoR = OpenFifo(r_name, opn_size, opn_flags | FIFOF_READ);
  618.     han->ff_SRead->sr_Refs    = 1;
  619.     if (han->ff_FifoR == NULL)
  620.         return(-1);
  621.     }
  622.     if (han_flags & FHF_WRITE) {
  623.     han->ff_FifoW = OpenFifo(w_name, opn_size, opn_flags | FIFOF_WRITE);
  624.     if (han->ff_FifoW == NULL)
  625.         return(-1);
  626.     }
  627.     return(0);
  628. }
  629.  
  630. void
  631. CloseHandle(han)
  632. FHan *han;
  633. {
  634.     Remove(&han->ff_Node);
  635.     if (han->ff_SRead) {
  636.     if (--han->ff_SRead->sr_Refs == 0) {
  637.         if (han->ff_FifoR)
  638.         CloseFifo(han->ff_FifoR, 0);
  639.         FreeMem(han->ff_SRead, sizeof(SharRead));
  640.     }
  641.     han->ff_SRead = NULL;
  642.     }
  643.     if (han->ff_FifoW) {
  644.     if (han->ff_Flags & FHF_CLOSEEOF)
  645.         CloseFifo(han->ff_FifoW, FIFOF_EOF);
  646.     else
  647.         CloseFifo(han->ff_FifoW, 0);
  648.     han->ff_FifoW = NULL;
  649.     }
  650.     if (han->ff_Port) {
  651.     FreeMem(han->ff_Port, sizeof(MsgPort) + sizeof(Interrupt));
  652.     han->ff_Port = NULL;
  653.     }
  654.     if (han->ff_CookBuf)
  655.     FreeMem(han->ff_CookBuf, CB_SIZE);
  656.     FreeMem(han, sizeof(FHan) + strlen(han->ff_Node.ln_Name) + 1);
  657. }
  658.  
  659.  
  660. /*
  661.  *  handle cooked data by actually reading it from the fifo, echoing it
  662.  *  to the return channel (if it exists), and processing it.  If a <CR>
  663.  *  is processed, handle any
  664.  */
  665.  
  666. void
  667. HandleRequestMsg(msg)
  668. Message *msg;
  669. {
  670.     FHan *han = (FHan *)msg->mn_Node.ln_Name;
  671.  
  672.     if (msg == &han->ff_WrMsg) {
  673.     han->ff_Flags &= ~FHF_WAVAIL;
  674.     while (msg = RemHead((MaxList *)&han->ff_WrWait))  /*  retry operation */
  675.         PutMsg(PktPort, msg);
  676.  
  677.     /*
  678.      *  if we were blocked trying to echo, then read data pending,
  679.      *  make sure read-request is queued and will be retried.
  680.      */
  681.  
  682.     if (han->ff_Flags & FHF_COOKECHOBLK) {
  683.         if ((han->ff_Flags & FHF_RPEND) == 0) {
  684.         RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  685.         han->ff_Flags |= FHF_RPEND;
  686.         }
  687.         han->ff_Flags &= ~FHF_COOKECHOBLK;
  688.     }
  689.     } else if (msg == &han->ff_RdMsg) {
  690.     han->ff_Flags &= ~FHF_RPEND;
  691.     if (han->ff_Flags & FHF_COOKED) {
  692.         long n;
  693.         long i;
  694.         short rwakeup = 0;
  695.         char *ptr;
  696.  
  697.         n = ReadFifo(han->ff_FifoR, &ptr, 0);
  698.  
  699.         if (n < 0) {
  700.         han->ff_Flags |= FHF_REOF;
  701.         rwakeup = 1;
  702.         }
  703.  
  704.         for (i = 0; i < n; ++i) {
  705.         switch(ptr[i]) {
  706.         case 13:
  707.         case 10:
  708.             if (han->ff_CookIdx >= CB_SIZE - 2) {
  709.             han->ff_Flags |= FHF_COOKBFUL;
  710.             n = --i;
  711.             break;
  712.             }
  713.             if (han->ff_FifoW) {
  714.             if (WriteFifo(han->ff_FifoW, "\r\n", 2) != 2) {
  715.                 han->ff_Flags |= FHF_COOKECHOBLK;
  716.                 n = --i;
  717.                 break;
  718.             }
  719.             }
  720.             han->ff_CookBuf[han->ff_CookIdx++] = 0;
  721.             han->ff_CookBuf[han->ff_CookIdx] = 0;
  722.             han->ff_LRet = 1;
  723.             rwakeup = 1;
  724.             break;
  725.         case 8:
  726.             if (han->ff_CookIdx && han->ff_CookBuf[han->ff_CookIdx-1] != 0) {
  727.             if (han->ff_FifoW) {
  728.                 if (WriteFifo(han->ff_FifoW, "\010 \010", 3) != 3) {
  729.                 han->ff_Flags |= FHF_COOKECHOBLK;
  730.                 n = --i;
  731.                 break;
  732.                 }
  733.             }
  734.             han->ff_CookBuf[--han->ff_CookIdx] = 0;
  735.             if (han->ff_CookIdx && han->ff_CookBuf[han->ff_CookIdx-1] == 0)
  736.                 han->ff_LRet = 1;
  737.             }
  738.             break;
  739.         default:
  740.             if (han->ff_CookIdx >= CB_SIZE - 2) {
  741.             han->ff_Flags |= FHF_COOKBFUL;
  742.             n = --i;
  743.             break;
  744.             }
  745.             if (han->ff_FifoW) {
  746.             if (WriteFifo(han->ff_FifoW, ptr + i, 1) != 1) {
  747.                 han->ff_Flags |= FHF_COOKECHOBLK;
  748.                 n = --i;
  749.                 break;
  750.             }
  751.             }
  752.             han->ff_CookBuf[han->ff_CookIdx++] = ptr[i];
  753.             han->ff_CookBuf[han->ff_CookIdx] = 0;
  754.             han->ff_LRet = 0;
  755.             break;
  756.         }
  757.         }
  758.  
  759.         /*
  760.          *    if output was held due to cooked input pending, and the
  761.          *    case is no longer true, then restart output
  762.          */
  763.  
  764.         if ((han->ff_Flags & FHF_WIHOLD) && (han->ff_LRet || han->ff_CookIdx == 0)) {
  765.         han->ff_Flags &= ~FHF_WIHOLD;
  766.         while (msg = RemHead((MaxList *)&han->ff_WrWait))
  767.             PutMsg(PktPort, msg);
  768.         }
  769.  
  770.         if (i > 0) {
  771.         if (ReadFifo(han->ff_FifoR, &ptr, i) < 0) {
  772.             han->ff_Flags |= FHF_REOF;
  773.             rwakeup = 1;
  774.         }
  775.         }
  776.         if (n >= 0 && !(han->ff_Flags & (FHF_COOKECHOBLK|FHF_COOKBFUL|FHF_REOF))) {
  777.         RequestFifo(han->ff_FifoR, &han->ff_RdMsg, FREQ_RPEND);
  778.         han->ff_Flags |= FHF_RPEND;
  779.         }
  780.         if (!rwakeup)
  781.         return;
  782.     }
  783.     while (msg = RemHead((MaxList *)&han->ff_RdWait))  /*  retry operation */
  784.         PutMsg(PktPort, msg);
  785.     }
  786. }
  787.  
  788. void
  789. WaitMsg(msg)
  790. Message *msg;
  791. {
  792.     while (msg->mn_Node.ln_Type == NT_MESSAGE)
  793.     Wait(1 << msg->mn_ReplyPort->mp_SigBit);
  794.     Forbid();
  795.     Remove(&msg->mn_Node);
  796.     Permit();
  797. }
  798.  
  799. void
  800. SigHandles(name, sigs)
  801. char *name;
  802. long sigs;
  803. {
  804.     FHan *han;
  805.  
  806.     for (han = (FHan *)HanList.mlh_Head; han->ff_Node.ln_Succ; han = (FHan *)han->ff_Node.ln_Succ) {
  807.     if (strcmp(han->ff_Node.ln_Name, name) == 0 && han->ff_Task)
  808.         Signal(han->ff_Task, sigs);
  809.     }
  810. }
  811.  
  812.  
  813.  
  814. /*
  815.  *  PACKET ROUTINES.    Dos Packets are in a rather strange format as you
  816.  *  can see by this and how the PACKET structure is extracted in the
  817.  *  GetMsg() of the main routine.
  818.  */
  819.  
  820. void
  821. returnpacket(packet)
  822. DosPacket *packet;
  823. {
  824.     Message *mess;
  825.     MsgPort *replyPort;
  826.  
  827.     replyPort             = packet->dp_Port;
  828.     mess             = packet->dp_Link;
  829.     packet->dp_Port         = PktPort;
  830.     mess->mn_Node.ln_Name    = (char *)packet;
  831.     PutMsg(replyPort, mess);
  832. }
  833.  
  834. void
  835. Initialize()
  836. {
  837.     DeviceNode *dn;
  838.     Process *proc = FindTask(NULL);
  839.     DosPacket *packet;
  840.  
  841.     /*
  842.      *    Initialize port
  843.      */
  844.  
  845.     {
  846.     IoSink = CreatePort("FIFO-PORT", 0);
  847.     FreeSignal(IoSink->mp_SigBit);
  848.     IoSink->mp_SigBit = SIGBREAKB_CTRL_F;
  849.     }
  850.     PktPort = CreatePort(NULL, 0);
  851.     PktPortMask = 1 << PktPort->mp_SigBit;
  852.  
  853. #ifdef CLI_START
  854.  
  855.     /*
  856.      *    create DOS node
  857.      */
  858.  
  859.     MkDevice("FIFO");
  860.  
  861.     FifoBase = OpenLibrary("fifo.library", 0);
  862.  
  863. #else
  864.  
  865.     /*
  866.      *    Handle initial message.  We pull the message off the port before
  867.      *    calling OpenLibrary() so if OpenLibrary() makes a DOS call it
  868.      *    doesn't crash the machine (due to an unexpected packet).  This
  869.      *    will happen if the library needs to be loaded.    There is no other
  870.      *    safe time to do this.
  871.      */
  872.  
  873.     {
  874.     Message *msg;
  875.  
  876.     WaitPort(&proc->pr_MsgPort);
  877.     msg = GetMsg(&proc->pr_MsgPort);
  878.     packet = (DosPacket *)msg->mn_Node.ln_Name;
  879.     }
  880.  
  881.     /*
  882.      *    Fifo Library
  883.      */
  884.  
  885.     FifoBase = OpenLibrary("fifo.library", 0);
  886.  
  887.     {
  888.     DevNode = dn = BTOC(packet->dp_Arg3);
  889.  
  890.     dn->dn_Task = PktPort;
  891.     packet->dp_Res1 = (FifoBase) ? DOS_TRUE : DOS_FALSE;
  892.     packet->dp_Res2 = 0;
  893.     returnpacket(packet);
  894.     }
  895.  
  896. #endif
  897.  
  898.     if (FifoBase == NULL)
  899.     myexit(1);
  900. }
  901.  
  902.  
  903. void
  904. myexit(code)
  905. int code;
  906. {
  907. #ifdef CLI_START
  908.     DelDevice();
  909. #else
  910.  
  911.     /*
  912.      *    Device Node
  913.      */
  914.  
  915.     {
  916.     DeviceNode *dn = DevNode;
  917.  
  918.     dn->dn_Task = NULL;
  919.     dn->dn_SegList = NULL;
  920.     }
  921. #endif
  922.  
  923.     /*
  924.      *    delete ports
  925.      */
  926.  
  927.     if (IoSink) {
  928.     IoSink->mp_SigBit = AllocSignal(-1);
  929.     DeletePort(IoSink);
  930.     }
  931.  
  932.     if (PktPort)
  933.     DeletePort(PktPort);
  934.  
  935. #ifdef DEBUG
  936.     if (DBFifo) {
  937.     CloseFifo(DBFifo, FIFOF_EOF);
  938.     DBFifo = NULL;
  939.     }
  940. #endif
  941.     if (FifoBase) {
  942.     CloseLibrary(FifoBase);
  943.     FifoBase = NULL;
  944.     }
  945.     _exit(code);
  946. }
  947.  
  948.  
  949. MsgPort *
  950. SpecPort(han)
  951. FHan *han;
  952. {
  953.     MsgPort *port = AllocMem(sizeof(MsgPort) + sizeof(Interrupt), MEMF_CLEAR|MEMF_PUBLIC);
  954.     Interrupt *xint = (Interrupt *)(port + 1);
  955.     extern void AIntCode();
  956.  
  957.     NewList(&port->mp_MsgList);
  958.     port->mp_Node.ln_Name = (char *)han;
  959.     port->mp_Node.ln_Type = NT_MSGPORT;
  960.     port->mp_Flags = PA_SOFTINT;
  961.     port->mp_SigTask = (void *)xint;
  962.     xint->is_Node.ln_Type = NT_INTERRUPT;
  963.     xint->is_Node.ln_Pri  = -32;
  964.     xint->is_Data = (APTR)port;
  965.     xint->is_Code = AIntCode;
  966.     return(port);
  967. }
  968.  
  969. __geta4 __stkargs void
  970. IntCode(port)
  971. MsgPort *port;
  972. {
  973.     Message *msg;
  974.     DosPacket *packet;
  975.     FileHandle *fh;
  976.  
  977. #ifdef DEBUG
  978.     if (DDebug)
  979.     xprintf("port %08lx\n", port);
  980. #endif
  981.     while (msg = GetMsg(port)) {
  982.     packet = (DosPacket *)msg->mn_Node.ln_Name;
  983.  
  984. #ifdef DEBUG
  985.     if (DDebug)
  986.         xprintf("type %08lx\n", packet->dp_Type);
  987. #endif
  988.  
  989.  
  990.     switch(packet->dp_Type) {
  991.     case ACTION_FINDUPDATE:
  992.     case ACTION_FINDINPUT:
  993.     case ACTION_FINDOUTPUT:
  994.         fh = BTOC(packet->dp_Arg1);
  995.         fh->fh_Port = port;
  996.         break;
  997.     case ACTION_SCREEN_MODE:
  998.         packet->dp_Arg2 = port;
  999.         break;
  1000.     }
  1001.     PutMsg(PktPort, msg);
  1002.     }
  1003. }
  1004.  
  1005. #ifdef DEBUG
  1006.  
  1007. void
  1008. xprintf(char *ctl, ...)
  1009. {
  1010.     va_list va;
  1011.     static char buf[256];
  1012.     int n;
  1013.  
  1014.     if (DBFifo) {
  1015.     va_start(va, ctl);
  1016.     n = vsprintf(buf, ctl, va);
  1017.     if (n > 0)
  1018.         WriteFifo(DBFifo, buf, n);
  1019.     va_end(va);
  1020.     }
  1021. }
  1022.  
  1023. #endif
  1024.  
  1025. #ifdef CLI_START
  1026.  
  1027. /*
  1028.  *  DEVICE CREATION AND DELETION
  1029.  */
  1030.  
  1031. DosList *Dl;
  1032.  
  1033. void
  1034. MkDevice(devName)
  1035. char *devName;
  1036. {
  1037.     DosList *dl;
  1038.     RootNode *root;
  1039.     DosInfo *info;
  1040.  
  1041.     Dl = dl = (struct DosList *)DosAllocMem(sizeof(struct DosList)+strlen(devName)+2);
  1042.     strcpy((char *)(dl+1) + 1, devName);
  1043.     *(char *)(dl + 1) = strlen(devName);
  1044.     dl->dol_Type = DLT_DEVICE;
  1045.     dl->dol_Task = PktPort;
  1046.     dl->dol_Name = MKBADDR((char *)(dl+1));
  1047.  
  1048.     Forbid();
  1049.     root  = (struct RootNode *)DOSBase->dl_Root;
  1050.     info  = (struct DosInfo  *)BADDR(root->rn_Info);
  1051.     dl->dol_Next = info->di_DevInfo;
  1052.     info->di_DevInfo = MKBADDR(dl);
  1053.     Permit();
  1054. }
  1055.  
  1056. void
  1057. DelDevice()
  1058. {
  1059.     DosList *dl;
  1060.     DosInfo *info;
  1061.     RootNode *root;
  1062.     DosList *dls;
  1063.     BPTR    *bpp;
  1064.  
  1065.     if (dl = Dl) {
  1066.     Forbid();
  1067.     root  = (struct RootNode *)DOSBase->dl_Root;
  1068.     info  = (struct DosInfo  *)BADDR(root->rn_Info);
  1069.  
  1070.     for (bpp = &info->di_DevInfo; dls = BADDR(*bpp); bpp = &dls->dol_Next) {
  1071.         if (dls == dl)
  1072.         break;
  1073.     }
  1074.     if (dls == dl) {
  1075.         *bpp = dls->dol_Next;
  1076.     } else {
  1077.         Alert(0x07AAAAAA|AT_Recovery);
  1078.     }
  1079.     Permit();
  1080.     DosFree(dl);
  1081.     Dl = NULL;
  1082.     }
  1083. }
  1084.  
  1085. void *
  1086. DosAllocMem(bytes)
  1087. long bytes;
  1088. {
  1089.     long *ptr;
  1090.  
  1091.     bytes += 4;
  1092.  
  1093.     if (ptr = AllocMem(bytes, MEMF_PUBLIC | MEMF_CLEAR)) {
  1094.     *ptr++ = bytes;
  1095.     return((void *)ptr);
  1096.     }
  1097.     Alert(AG_NoMemory|AT_DeadEnd);
  1098. }
  1099.  
  1100. void
  1101. DosFree(vptr)
  1102. void *vptr;
  1103. {
  1104.     long *ptr = vptr;
  1105.     --ptr;
  1106.     FreeMem(ptr, *ptr);
  1107. }
  1108.  
  1109. #endif
  1110.